/*
 * AbstractAccount.java
 *
 *
 */
package banksimulator.bank;

import java.util.List;
import javax.swing.event.EventListenerList;

/**
 * <p>定义帐户的一般行为。
 * <br>AbstractAccount类用来存取基本帐户信息。
 * <p><b>注意：</b>每一个帐户应该有一个与其他帐户不同的唯一的ID。
 * 帐户ID应该使用AccountFactory接口的nextAccountID方法获得。
 * @author Rajab Ma
 * @see AccountFactory#nextAccountID()
 *
 */
public abstract class AbstractAccount {

    /** 事件监视器列表。存放各个监听银行存放帐户变动情况的监听器 */
    protected EventListenerList listenerList = new EventListenerList();

    /**
     * 获取帐户的余额。
     * @return 帐户余额
     */
    public abstract double getBalance();

    /**
     * 获取帐户的用户名。
     * @return 帐户的用户名
     */
    public abstract String getUserName();

    /**
     * 设置帐户的用户名。
     * @param userName 帐户的用户名
     */
    public abstract void setUserName(String userName);

    /**
     * 获取当前帐户的ID。
     * @return 帐户的ID
     */
    public abstract String getAccountID();

    /**
     * 从当前帐户取出指定数额的存款。
     * <br><b>注意:</b>子类在实现此方法时，若余额发生变化，应调用fireAccountChange方法，
     * 通知所有注册的监听器余额已经发生了变化。
     * @param amount 要取出的存款金额
     * @throws FundsInsufficientException 当帐户余额不足以支付存取的金额时
     * @see AbstractAccount#fireAccountChange(double, double)
     */
    public abstract void withdraw(double amount) throws FundsInsufficientException;

    /**
     * 往当前帐户存入指定数额的存款。
     * <br><b>注意:</b>子类在实现此方法时，若余额发生变化，应调用fireAccountChange方法，
     * 通知所有注册的监听器余额已经发生了变化。
     * @param amount 存款的金额
     * @see AbstractAccount#fireAccountChange(double, double)
     */
    public abstract void deposit(double amount);

    /**
     * 获取帐户的所有交易记录。
     * @return 交易记录列表
     */
    public abstract List<Transaction> allTranscation();

    /**
     * 通知帐户的余额发生了变化。
     * <p><b>注意:</b>子类实现withdraw方法、deposit方法时，
     * 应调用此方法通知所有注册的监听器进行相应的处理。
     * @param before 帐户发生变化前的余额
     * @param after 帐户发生变化后的余额
     */
    protected void fireAccountChange(double before, double after) {

        AccountChangeEvent evt = new AccountChangeEvent(this, before, after);
        for (Object listener : listenerList.getListenerList()) {
            if (listener instanceof AccountChangeListener) {
                ((AccountChangeListener) listener).accountChanged(evt);
            }
        }
    }

    /**
     * 注册一个账户更改监听器。
     * <p>通过注册该监听器，可以在帐户的余额发生变动时得到通知并执行某种操作，如：
     * <pre>
     * account.addAccountChangeListener(new AccountChangeListener() {
     *      public void accountChanged(AccountChangeEvent evt) {
     *           //处理代码
     *      }
     *  });
     * </pre>
     * @param listener　要注册的账户更改监听器
     */
    public void addAccountChangeListener(AccountChangeListener listener) {
        listenerList.add(AccountChangeListener.class, listener);
    }

    /**
     * 移除一个已注册的账户更改监听器。
     * @param listener 要移除的账户更改监听器
     */
    public void removeAccountChangeListener(AccountChangeListener listener) {
        listenerList.remove(AccountChangeListener.class, listener);
    }

    /**
     * 返回该对象的字符串表示。
     * @return 该对象的字符串表示形式
     */
    @Override
    public abstract String toString();

    /**
     * 指示其他某个对象是否与此对象“相等”。
     * @param obj 要与之比较的引用对象
     * @return 如果此对象与 obj 参数相同，则返回 true；否则返回 false
     */
    @Override
    public abstract boolean equals(Object obj);

    /**
     * 返回该对象的哈希码值。
     * @return 此对象的一个哈希码值
     */
    @Override
    public int hashCode() {
        return super.hashCode();
    }
}
